package com.lee.shiro.realm;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import com.alibaba.dubbo.config.annotation.Reference;
import com.lee.constant.ShiroConstants;
import com.lee.exception.CaptchaException;
import com.lee.shiro.service.PasswordService;
import com.lee.system.api.IMenuService;
import com.lee.system.api.IRoleService;
import com.lee.system.api.IUserService;
import com.lee.system.entity.User;
import com.lee.utils.DateUtils;
import com.lee.utils.ServletUtils;
import com.lee.utils.ShiroUtils;

/**
 * 自定义Realm 处理登录 权限
 * 
 * @author LiPengFei
 *
 */
public class UserRealm extends AuthorizingRealm {
	private static final Logger log = LoggerFactory.getLogger(UserRealm.class);

	@Reference
	private IMenuService menuService;

	@Reference
	private IRoleService roleService;

	@Reference
	private IUserService uerService;

	@Autowired
	PasswordService passwordService;

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		Long userId = ShiroUtils.getUserId();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 角色加入AuthorizationInfo认证对象
		info.setRoles(roleService.selectRoleKeys(userId));
		// 权限加入AuthorizationInfo认证对象
		info.setStringPermissions(menuService.selectPermsByUserId(userId));
		return info;
	}

	/**
	 * 登录认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		String loginName = upToken.getUsername();
		String password = "";
		if (upToken.getPassword() != null) {
			password = new String(upToken.getPassword());
		}
		User user = null;
		try {
			// 验证码校验
			if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) {
				throw new CaptchaException();
			}
			user = uerService.selectByLoginName(loginName);
			// 密码验证
			passwordService.validate(user, password);
			// 账号不存在
			if (user == null || "2".equals(user.getDelFlag())) {
				throw new UnknownAccountException("用户不存在/密码错误");
			}
			if ("1".equals(user.getStatus())) {
				throw new LockedAccountException("账号已被锁定,请联系管理员");
			}
			user.setLoginIp(ShiroUtils.getIp());
			user.setLoginDate(DateUtils.getNowDate());
			uerService.updateUser(user);

		} catch (Exception e) {
			log.info("对用户[" + loginName + "]进行登录验证..验证未通过{}", e.getMessage());
			throw new AuthenticationException(e.getMessage(), e);
		}
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
		return info;
	}

	/**
	 * 清理缓存权限
	 */
	public void clearCachedAuthorizationInfo() {
		this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
	}

}
